package com.pithypan.controller;

import com.pithypan.common.Constants;
import com.pithypan.common.ResponseCodeEnum;
import com.pithypan.common.exceptionHandler.MyException;
import com.pithypan.common.utils.R;
import com.pithypan.common.utils.RedisUtils;
import com.pithypan.common.utils.StringTools;
import com.pithypan.convert.RegisterVoConvert;
import com.pithypan.dto.CreateImageCode;
import com.pithypan.dto.SessionWebUserDto;
import com.pithypan.dto.SysSettingsDto;
import com.pithypan.dto.UserSpaceDto;
import com.pithypan.entity.UserInfo;
import com.pithypan.mapper.FileInfoMapper;
import com.pithypan.service.EmailCodeService;
import com.pithypan.service.UserInfoService;
import com.pithypan.vo.RegisterVo;
import com.pithypan.vo.ResetPwdVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;

/**
 * <p>
 * 用户信息 前端控制器   测试账号1509905481@qq.com，Q7777777
 * </p>
 *
 * @author author
 * @since 2023-08-17
 */
@RestController
//@RequestMapping("/api")   //已在application.properties匹配文件中配置
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;
    @Resource
    private EmailCodeService emailCodeService;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private FileInfoMapper fileInfoMapper;

    @Value("${project.folder}")
    private String projectFolder;      //存放头像的路径

    private static final Logger logger = LoggerFactory.getLogger(UserInfoController.class);
    private static final String CONTENT_TYPE = "Content-Type";
    private static final String Content_TYPE_VALUE = "application/json;charset=UTF-8";


    /**
     * 图片验证码生成
     * @param response
     * @param session
     * @param type    0：生成页面图片验证码   其它：生成弹窗图片验证码
     * @throws IOException
     */
    @RequestMapping("/checkCode")
    public void checkCode(HttpServletResponse response, HttpSession session, Integer type) throws IOException {
        CreateImageCode vCode = new CreateImageCode(130, 38, 5, 10);
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        String code = vCode.getCode();    //getCode() 将生成的验证码转换为小写
        if (type == null || type == 0) {
            session.setAttribute(Constants.CHECK_CODE_KEY, code);   //页面图片验证码
        } else {
            session.setAttribute(Constants.CHECK_CODE_KEY_EMAIL, code); //弹窗图片验证码
        }
        vCode.write(response.getOutputStream());
    }


    /**
     * 发送邮箱验证码
     * @param session
     * @param email        请求验证码的邮箱
     * @param checkCode    发送邮箱验证码前需校验的图片验证码
     * @param type         0:用户注册   1:修改密码
     * @return
     */
    @RequestMapping("/sendEmailCode")
    public R sendEmailCode(HttpSession session, String email, String checkCode, int type) {
        try {
            //校验图片验证码,不考虑大小写
            if (!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY_EMAIL))) {
                throw new MyException(ResponseCodeEnum.CODE_602.getCode(), ResponseCodeEnum.CODE_602.getMsg());
            }
            emailCodeService.sendEmailCode(email, type);
            return R.ok();

        } finally {
            session.removeAttribute(Constants.CHECK_CODE_KEY_EMAIL); //不管成功与否，删除验证码
        }
    }


    /**
     * 注册
     * @param session
     * @param registerVo  邮箱、昵称、加密的密码、图片验证码、邮箱验证码
     * @return
     */
    @RequestMapping("/register")
    public R register(HttpSession session, @RequestBody RegisterVo registerVo) {
        try {
            //校验图片验证码，不考虑大小写
            if (!registerVo.getCheckCode().equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY))) {
                throw new MyException(ResponseCodeEnum.CODE_602.getCode(), ResponseCodeEnum.CODE_602.getMsg());
            }

            //将vo转换为entity
            UserInfo userInfo = RegisterVoConvert.INSTANCE.vo2entity(registerVo);
            userInfo.setPassword(registerVo.getReRegisterPassword());

            userInfoService.register(userInfo, registerVo.getEmailCode());
            return R.ok();
        } finally {
            session.removeAttribute(Constants.CHECK_CODE_KEY);   //删除验证码
        }
    }


    /**
     * 用户登陆
     * @param session
     * @param email      邮箱
     * @param password   加密后的密码
     * @param checkCode  用户提交的图片验证码
     * @return
     */
    @RequestMapping("/login")
    public R login(HttpSession session, String email, String password, String checkCode) {
        try {
            //校验图片验证码，不考虑大小写
            if (!checkCode.equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY))) {
                throw new MyException(ResponseCodeEnum.CODE_602.getCode(), ResponseCodeEnum.CODE_602.getMsg());
            }

            //登陆
            SessionWebUserDto sessionWebUserDto = userInfoService.login(email, password);
            session.setAttribute(Constants.SESSION_KEY, sessionWebUserDto);      //将登陆信息存入session

            return R.ok().data("userInfo", sessionWebUserDto);
        } finally {
            session.removeAttribute(Constants.CHECK_CODE_KEY);   //删除验证码
        }
    }


    /**
     * 找回密码（用户未登陆，需要邮箱验证）
     * @param session
     * @param resetPwdVo 邮箱、加密的密码、图片验证码、邮箱验证码
     */
    @RequestMapping("/resetPwd")
    public void resetPwd(HttpSession session, @RequestBody ResetPwdVo resetPwdVo) {
        try {
            //校验图片验证码，不考虑大小写
            if (!resetPwdVo.getCheckCode().equalsIgnoreCase((String) session.getAttribute(Constants.CHECK_CODE_KEY))) {
                throw new MyException(ResponseCodeEnum.CODE_602.getCode(), ResponseCodeEnum.CODE_602.getMsg());
            }

            userInfoService.resetPwd(
                    resetPwdVo.getEmail(),
                    resetPwdVo.getReRegisterPassword(),
                    resetPwdVo.getEmailCode());

        } finally {
            session.removeAttribute(Constants.CHECK_CODE_KEY);   //删除验证码
        }
    }


    /**
     * 获取用户头像
     * @param response
     * @param userId   用户id
     */
    @RequestMapping("/getAvatar/{userId}")
    public void getAvatar(HttpServletResponse response, @PathVariable("userId") String userId) {
        String avatarFolderName = "/file/avatar/";
        File folder = new File(projectFolder + avatarFolderName);  //存放头像的路径
        if (!folder.exists()) {      //判断目录是否存在
            folder.mkdirs();         //不存在则创建
        }

        String avatarPath = projectFolder + avatarFolderName + userId + ".jpg"; //用户头像
        File file = new File(avatarPath);
        if (!file.exists()) {   //判断用户头像是否存在
            //判断默认头像是否存在
            if (!new File(projectFolder + avatarFolderName + "default_avatar.jpg").exists()) {
                this.printNoDefaultImage(response);   //提示放置默认头像
            }
            avatarPath = projectFolder + avatarFolderName + "default_avatar.jpg"; //选取默认头像
        }
        response.setContentType("image/jpg");  //响应体数据格式
        this.readFile(response, avatarPath);   //通过字节流读取头像，并写入网页中
    }


    /**
     * 获取登陆用户信息
     * @param session
     * @return
     */
    @RequestMapping("/getUserInfo")
    public R getUserInfo(HttpSession session) {
        //从session中获取登陆用户信息
        SessionWebUserDto sessionWebUserDto = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);
        return R.ok().data("userInfo", sessionWebUserDto);
    }


    /**
     * 获取用户内存空间信息
     * @param session
     * @return
     */
    @RequestMapping("/getUseSpace")
    public R getUseSpace(HttpSession session) {
        //从session中获取登陆用户信息
        SessionWebUserDto sessionWebUserDto = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);

        //先从redis缓存中获取邮件模板
        SysSettingsDto sysSettingsDto = (SysSettingsDto) redisUtils.get(Constants.REDIS_KEY_SYS_SETTING);
        //缓存中没有邮件，则根据默认模版创建一封邮件并存入redis中
        if (sysSettingsDto == null) {
            sysSettingsDto = new SysSettingsDto();
            redisUtils.set(Constants.REDIS_KEY_SYS_SETTING, sysSettingsDto);
        }

        String userId = sessionWebUserDto.getUserId();
        //从redis中查询用户的内存空间信息
        UserSpaceDto spaceDto = (UserSpaceDto) redisUtils.get(Constants.REDIS_KEY_USER_SPACE_USE + userId);
        if (spaceDto == null) {
            spaceDto = new UserSpaceDto();
            Long useSpace = userInfoService.getUserSpace(userId);
            spaceDto.setUseSpace(useSpace);
            spaceDto.setTotalSpace(sysSettingsDto.getUserInitUserSpace() * 1024 * 1024L); //设置用户总空间/MB
            redisUtils.set(Constants.REDIS_KEY_USER_SPACE_USE + userId, spaceDto);
        }

        return R.ok().data("spaceDto", spaceDto);
    }


    /**
     * 退出登陆
     * @param session
     * @return
     */
    @RequestMapping("/logout")
    public R logout(HttpSession session) {
        session.invalidate();
        return R.ok();
    }


    /**
     * 修改用户头像
     * @param session
     * @param avatar
     * @return
     */
    @RequestMapping("/updateUserAvatar")
    public R updateUserAvatar(HttpSession session, MultipartFile avatar) {
        //从session中获取登陆用户信息
        SessionWebUserDto sessionWebUserDto = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);

        String avatarFolderName = "/file/avatar/";
        System.out.println("--------------------" + projectFolder + avatarFolderName);
        File targetFileFolder = new File(projectFolder + avatarFolderName);
        if (!targetFileFolder.exists()) {   //判断目录是否存在
            targetFileFolder.mkdirs();      //不存在则创建目录
        }

        System.out.println("************" + targetFileFolder);
        System.out.println("----------------------" + targetFileFolder.getPath() + "/" + sessionWebUserDto.getUserId() + ".jpg");
        File targetFile = new File(targetFileFolder.getPath() + "/" + sessionWebUserDto.getUserId() + ".jpg");
        try {
            avatar.transferTo(targetFile);   //上传头像
        } catch (Exception e) {
            logger.error("修改头像失败");
        }

        UserInfo updateInfo = new UserInfo();
        updateInfo.setQqAvatar("");            //将QQ头像重置为空
        userInfoService.updateUserAvatarByUserId(updateInfo, sessionWebUserDto.getUserId());
        sessionWebUserDto.setAvatar(null);
        session.setAttribute(Constants.SESSION_KEY, sessionWebUserDto);   //更新session
        return R.ok();
    }


    /**
     * 修改密码（用户已登陆，无需邮箱验证）
     * @param session
     * @param password
     * @return
     */
    @RequestMapping("/updatePassword")
    public R updatePassword(HttpSession session, String password) {
        //从session中获取登陆用户信息
        SessionWebUserDto sessionWebUserDto = (SessionWebUserDto) session.getAttribute(Constants.SESSION_KEY);
        UserInfo updateInfo = new UserInfo();
        updateInfo.setPassword(StringTools.encodeByMd5(password));  //设置新密码
        userInfoService.updatePasswordByUserId(updateInfo, sessionWebUserDto.getUserId());
        return R.ok();
    }


//---------------------------------------------------------------------------------------


    //IO读取头像文件，并写入网页中 -- getAvatar获取用户头像方法中使用
    protected void readFile(HttpServletResponse response, String filePath) {
        if (!StringTools.pathIsOk(filePath)) {  //判断路径是否合理
            return;
        }

        OutputStream out = null;
        FileInputStream in = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return;
            }

            byte[] byteData = new byte[1024];
            in = new FileInputStream(file);     //创建读取的文件流
            out = response.getOutputStream();   //由response创建out流
            int len = 0;
            while ((len = in.read(byteData)) != -1) {
                out.write(byteData, 0, len);
            }
            out.flush();
        } catch (Exception e) {
            logger.error("读取文件失败", e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    logger.error("out -- IO异常", e);
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error("in -- IO异常", e);
                }
            }
        }
    }


    //提示放置默认头像 -- getAvatar获取用户头像方法中使用
    private void printNoDefaultImage(HttpServletResponse response) {
        response.setHeader(CONTENT_TYPE, Content_TYPE_VALUE);
        response.setStatus(HttpStatus.OK.value());
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
            writer.print("请在头像目录下放置默认头像-default_avatar.jpg");
            writer.close();
        } catch (Exception e) {
            logger.error("输出默认头像失败", e);
        } finally {
            writer.close();
        }
    }


}
